package com.mjsoftking.aopapp.aop.aspect;

import android.util.Log;
import android.view.View;

import com.mjsoftking.aopapp.R;
import com.mjsoftking.aopapp.aop.anno.ClickLimit;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;

/**
 * 用途：
 * <p>
 * 作者：mjSoftKing
 * 时间：2021/04/23
 */
@Aspect
public class ClickLimitAspect {

    private final static String TAG = ClickLimitAspect.class.getSimpleName();

    @Around("execution(* android.view.View.OnClickListener.onClick(..))")
    public void processJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
        Log.w(TAG, "-----method is click--- ");
        try {
            Signature signature = joinPoint.getSignature();
            if (!(signature instanceof MethodSignature)) {
                Log.d(TAG, "method is no MethodSignature, so proceed it");
                joinPoint.proceed();
                return;

            }

            MethodSignature methodSignature = (MethodSignature) signature;
            Method method = methodSignature.getMethod();
            boolean isHasLimitAnnotation = method.isAnnotationPresent(ClickLimit.class);
            String methodName = method.getName();
            int intervalTime = 500;
            // 这里判断是否使用了 ClickLimit 注解
            // 如果用注解，并且修改了限制点击的时间
            // 如果时间 <= 0 ，代表着不做限制，直接执行
            // 如果是其他时间，则更新限制时间
            if (isHasLimitAnnotation) {
                ClickLimit clickLimit = method.getAnnotation(ClickLimit.class);
                int limitTime = clickLimit.value();
                // not limit click
                if (limitTime <= 0) {
                    Log.d(TAG, "method: " + methodName + " limitTime is zero, so proceed it");
                    joinPoint.proceed();
                    return;
                }
                intervalTime = limitTime;
                Log.w(TAG, "methodName " + methodName + " intervalTime is " + intervalTime);
            }

            // 传进来的参数不是 View, 则直接执行
            Object[] args = joinPoint.getArgs();
            View view = getViewFromArgs(args);
            if (view == null) {
                Log.w(TAG, "view is null, proceed");
                joinPoint.proceed();
                return;
            }

            // 通过 viewTag 存储上次点击的时间
            Object viewTimeTag = view.getTag(R.integer.click_limit_tag_view);
            // first click viewTimeTag is null.
            if (viewTimeTag == null) {
                Log.w(TAG, "lastClickTime is zero , proceed");
                proceedAnSetTimeTag(joinPoint, view);
                return;
            }

            long lastClickTime = (long) viewTimeTag;
            if (lastClickTime <= 0) {
                Log.w(TAG, "lastClickTime is zero , proceed");
                proceedAnSetTimeTag(joinPoint, view);
                return;
            }

            // in limit time
            if (!canClick(lastClickTime, intervalTime)) {
                Log.w(TAG, "is in limit time , return");
                return;

            }
            proceedAnSetTimeTag(joinPoint, view);
            Log.w(TAG, "view proceed.");
        } catch (Throwable e) {
            e.printStackTrace();
            Log.w(TAG, e.getMessage());
            joinPoint.proceed();
        }
    }

    private boolean canClick(long lastClickTime, int intervalTime) {
        return (System.currentTimeMillis() - lastClickTime) > intervalTime;
    }

    /**
     * 只识别第一个参数是不是click事件的view
     * @param args
     * @return
     */
    private View getViewFromArgs(Object[] args) {
        if(null == args) return null;

        return args[0] instanceof View ? (View) (args[0]) : null;
    }

    private void proceedAnSetTimeTag(ProceedingJoinPoint joinPoint, View view) throws Throwable {
        view.setTag(R.integer.click_limit_tag_view, System.currentTimeMillis());
        joinPoint.proceed();
    }

}
